home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / flc2.arc / FLEXLIST.DOC < prev    next >
Text File  |  1990-12-07  |  45KB  |  966 lines

  1.  
  2.  
  3.  
  4.  
  5.                    FlexList II for ANSI C
  6.  
  7.  
  8.                                     Copyright 1990
  9.                                     John W. Small
  10.                                  All rights reserved
  11.  
  12.                                  PSW / Power SoftWare
  13.                                     P.O. Box 10072
  14.                              McLean, Virginia 22102 8072
  15.                                     (703) 759-3838
  16.  
  17.                                        10/4/90
  18.  
  19.  
  20.  
  21.                            CLAIM TO PROPRIETARY TECHNIQUES
  22.  
  23.           Several features  of FlexList  used in combination  make FlexList
  24.           unique  and versatile.   The  hybrid  stack-queue-list-array data
  25.           structure  and the techniques used  to implement it  as a generic
  26.           polymorphic  object  can  be  easily  ported  to  other  computer
  27.           languages  and remain intact in their essence.  The author claims
  28.           all rights to these features.
  29.  
  30.  
  31.                                    SHAREWARE NOTICE
  32.  
  33.           This FlexList packet is offered to you as "shareware" meaning try
  34.           before you  buy.   The shareware version  allows you to  test the
  35.           product  to see if it's suitable for  your purposes.  In order to
  36.           legally use FlexList for any other purpose you must first license
  37.           it from  PSW / Power SoftWare by sending in a registration fee of
  38.           $79.95.   Upon registration you will receive a printed version of
  39.           the complete manual (140+ pages)  and both ANSI C and  K&R source
  40.           code.
  41.  
  42.  
  43.                                    SHAREWARE MANUAL
  44.  
  45.           The shareware documentation that follows has been taken  from the
  46.           actual printed FlexList manual.  I've include only the most vital
  47.           information.     Refer  to   flexlist.h  for   FlexList  function
  48.           prototypes.    Flexlist.c  contains  comments  that  explain  the
  49.           virtual functions: FNnew, FNwrite, FNread, and FNdestruct.
  50.  
  51.  
  52.  
  53.  
  54.  
  55.                                      Introduction
  56.  
  57.  
  58.           A FlexList is alot more  than just a ready-to-run C linked  list.
  59.           It's  a   searchable-sortable-implodable  generic  heterogeneous-
  60.           homogeneous  hybrid  stack-queue-list-array accessible  by value,
  61.           reference or node.
  62.  
  63.           Anytime  your C  application requires a  stack, queue,  or linked
  64.           list, simply  include flexlist.h  in your  source  code and  then
  65.           start defining your  stack, queue, and/or list  variables as type
  66.           FlexList.  A FlexList can be  initialized, by various constructor
  67.           functions,  to store  any type  of data  and then  accessed  as a
  68.           stack, queue, list, or even an array interchangeably!
  69.  
  70.           With  more than  30 FlexList  functions to  choose from,  you can
  71.           push,  pop, insert, delete, sort, store, recall, or find, to name
  72.           but  a few.   Access your  data by  value (copy)  or by reference
  73.           (pointer).   Or move nodes  directly between FlexLists.   Because
  74.           FlexList functions  adjust  automatically to  different types  of
  75.           data, new sets  of primitives needn't  be derived to  accommodate
  76.           new data types.   Thus  your application's coding  time and  code
  77.           size won't  continue to grow when you add new types of FlexLists.
  78.           A FlexList can even be made to accommodate heterogeneous data via
  79.           its virtual function hooks.
  80.  
  81.           With FlexList you can  quickly construct lists of lists  or other
  82.           composite structures.  And since FlexLists are initialized at run
  83.           time, the data  they hold or even their creation can be specified
  84.           at  run  time thus  allowing your  application new  dimensions of
  85.           adaptability to user inputs.  
  86.  
  87.           Use  FlexList to  code your  next application's  linked  lists in
  88.           minutes  instead  of  days,   without  the  usual  debugging  and
  89.           documenting headaches associated with  custom coding various list
  90.           types.   It's no problem modifying your  application in midstream
  91.           to incorporate various and differing list types; with FlexList no
  92.           linked list code  needs to be  scrapped or rewritten.   The  code
  93.           space you'll save over cloning list primitives for different data
  94.           types  may just save you  from having to  go the overlay/swapping
  95.           route.
  96.  
  97.  
  98.  
  99.  
  100.  
  101.           Chapter  2.    Programming with FlexList
  102.  
  103.  
  104.           This chapter  is a combination of  a brief tutorial on  using the
  105.           FlexList tool  and a logical  survey of  the FlexList  functions.
  106.           You may find  it useful to  lookup the FlexList functions  in the
  107.           reference chapter while reading the example programs here.  Don't
  108.           worry too  much about  the details for  now.  Instead  you should
  109.           finish this chapter with 
  110.  
  111.           1)   an idea  of the  points to  remember  when programming  with
  112.                FlexList, 
  113.  
  114.           2)   a  conceptual model  of FlexList's  hybrid stack-queue-list-
  115.                array data structure, and
  116.  
  117.           3)   an  appreciation for the various ways that a FlexList can be
  118.                manipulated and accessed, namely: by value, by reference, or
  119.                by node.
  120.  
  121.           After  programming for a while  with FlexList, be  sure to reread
  122.           this chapter.
  123.  
  124.           Let's first cover  several points  that you should  keep in  mind
  125.           when using FlexList in any application.
  126.  
  127.           1.   Include flexlist.h in any application using FlexList.  
  128.  
  129.                     #include <flexlist.h>
  130.  
  131.           2.   Define your stack, queue, or list as a FlexList.
  132.  
  133.                     FlexList intStack;
  134.  
  135.           3.   Before  using  your FlexList  you  must  call a  constructor
  136.                function to initialize it  for the size of the data that you
  137.                will be storing in it.
  138.  
  139.                     FLfixed(&intStack,sizeof(int));
  140.  
  141.           4.   The address  of your FlexList  must be passed  as the  first
  142.                parameter to  FlexList functions.    Where  data copying  is
  143.                involved,  the address of the  data is passed  as the second
  144.                parameter.  Remember, don't pass the data by value.
  145.  
  146.                     for (i = 1; i < 11; i++)
  147.                          FLpushD(&intStack,&i);   /* address of i */
  148.  
  149.  
  150.  
  151.  
  152.  
  153.           5.   FlexList functions return pointers  or integers.  A returned
  154.                value of zero indicates failure of the function to carry out
  155.                its task.
  156.  
  157.                     while (FLpopD(&intStack,&i)) /* loop until false */
  158.                          printf("\n %d",i);
  159.  
  160.           6.   After  you are finished with your FlexList you should call a
  161.                FlexList  destructor  function.   In  our  example it  isn't
  162.                really necessary  since we've  popped all the  nodes anyway.
  163.                Let's include it though for completeness.
  164.  
  165.                     FLclear(&intStack);
  166.  
  167.           7.   Don't forget to link your application with the object module
  168.                created  by compiling  flexlist.c  or with  the library  you
  169.                build.
  170.  
  171.           Let's see the whole program.
  172.  
  173.  
  174.                #include <stdio.h>       /*  printf()  */
  175.                #include <flexlist.h>
  176.  
  177.                main()  /*  Count backwards from ten via a stack. */
  178.                {
  179.                     FlexList intStack;
  180.                     int i;
  181.  
  182.                     (void) FLfixed(&intStack,sizeof(int));
  183.                     for (i = 1; i < 11; i++)
  184.                          (void) FLpushD(&intStack,&i);
  185.                     while (FLpopD(&intStack,&i))
  186.                          (void) printf("\n %d",i);
  187.                     (void) FLclear(&intStack);
  188.                     return 0;
  189.                }
  190.  
  191.  
  192.                             Dynamic FlexList Constructors
  193.  
  194.           Let's  continue with  a survey  of FlexList's  various functions.
  195.           The FlexList  tool has several  constructor/destructor functions.
  196.           Why?  Well the FlexList that we just used in the previous example
  197.           is a  local variable.   Actually  only the FlexList  header is  a
  198.           local  variable -  the  nodes in  a  FlexList are  almost  always
  199.           dynamically  allocated!    Suppose  that  we  want  the  FlexList
  200.           variable itself to be  dynamically allocated?  Then we  would use
  201.           the constructor function FLfixedNew.
  202.  
  203.  
  204.  
  205.  
  206.  
  207.           Let's see that program again.
  208.  
  209.                #include <stdio.h>       /*  printf()  */
  210.                #include <flexlist.h>
  211.  
  212.                main()  /*  Count backwards from ten via a stack. */
  213.                {
  214.                     FlexL intS;
  215.                     int i;
  216.  
  217.                     if ((intS = FLfixedNew(sizeof(int),0,FLDdestruct0))
  218.                          == FlexL0)  return 1;
  219.                     for (i = 1; i < 11; i++)
  220.                          (void) FLpushD(intS,&i);
  221.                     while (FLpopD(intS,&i))
  222.                          (void) printf("\n %d",i);
  223.                     (void) FLdelete(&intS);
  224.                     return 0;
  225.                }
  226.  
  227.           Notice  that the  integer  stack is  now  defined as  type  FlexL
  228.           instead  of FlexList.   FlexL  is  a pointer  to a  FlexList.   I
  229.           contracted  intStack to  intS also  as a  reminder  that it  is a
  230.           pointer  to a  FlexList  and not  a  FlexList.   The  constructor
  231.       function  FLfixedNew  returns  a   pointer  to  the  FlexList  it
  232.       allocates  and  initializes,  otherwise  it  returns  0  or  more
  233.       specifically (FlexL)  0.  I've contracted all  NULL constants and
  234.       defined  them in flexlist.h, e.g.  (FlexL) 0 is  FlexL0.  Several
  235.       additional parameters  are also required by  FLfixedNew but don't
  236.       worry  about that now.  Please note that FlexList primitives take
  237.       a  FlexList pointer as their first  parameter, with the exception
  238.       of FLdelete.   That's why  I didn't use the  address of operator,
  239.       "&", with "intS"  in this version like I  did with "&intStack" in
  240.       the first.
  241.  
  242.           The  point  of  the  two  previous  examples  is  that   FlexList
  243.           constructor/destructor  functions come  in  two varieties:  those
  244.           that construct/destruct  FlexList  variables defined  at  compile
  245.           time,  i.e. local,  static,  and global  variables, versus  their
  246.           counter   parts   that   construct/destruct  FlexList   variables
  247.           dynamically allocated at run time.
  248.  
  249.  
  250.  
  251.  
  252.  
  253.                       FlexList Constructor/Destructor Functions
  254.  
  255.           1.   Constructor/destructor  functions  for FlexLists  defined at
  256.                compile time:
  257.  
  258.  
  259.                     FLfixed()      FLunpack()     FLvariant()
  260.                     FLstr()        FLclear()
  261.  
  262.  
  263.           2.   Constructor/destructor functions for FlexLists  allocated at
  264.                run time:
  265.  
  266.  
  267.                     FLfixedNew()   FLunpackNew()  FLvariantNew()
  268.                     FLstrNew()     FLdelete()
  269.  
  270.  
  271.           The FLunpack  and FLunpackNew  functions are  used  to explode  C
  272.           arrays (vectors) into FlexLists.  Each FlexNode holds one cell of
  273.       the array (see section  on compaction functions).   FLvariant and
  274.       FLvariantNew   construct  FlexLists   that  have   variant  sized
  275.       FlexNodes (see  FLvariant  in reference  chapter  to see  how  to
  276.       construct  heterogeneous FlexLists)!    FLstr and   FLstrNew  are
  277.       actually   macros   that    call   FLvariant   and   FLvariantNew
  278.       respectively, constructing FlexLists that contain  FlexNodes just
  279.       big be enough to hold C strings within.  FLclear  deallocates all
  280.       FlexNodes in  a FlexList, while  FLdelete calls FLclear  and then
  281.       proceeds   to  deallocate  the   dynamically  allocated  FlexList
  282.       variable (header).
  283.  
  284.  
  285.                            FlexList Header Access Functions
  286.  
  287.           As you become  more familiar  with what's inside  a FlexList  you
  288.           will want to access  the data fields inside the  FlexList header.
  289.           Never access  these fields directly!  There is little performance
  290.           penalty since most  of these functions  are in fact macros.   You
  291.           should decide  right now that  you are only  going to access  the
  292.           guts  of a  FlexList via  FlexList functions.   This  insures the
  293.           integrity  of the FlexList  by imposing the  OOP (Object Oriented
  294.           Programming) concept  of encapsulation.   The C  language doesn't
  295.           enforce access restriction as does the C++ language, so you're on
  296.           the honor system!
  297.  
  298.  
  299.  
  300.  
  301.  
  302.                FLfrontD()          FLcurrentD()        FLrearD()
  303.                FLcurNum()          FLnodes()           FLmaxNodes()
  304.                FLsetMaxNodes()     FLnotFull()         FLsizeofNodeData()
  305.                FLisSorted()        FLunSort()          FLcompare()
  306.                FLsetCompare()      FLisFixed()         FLisVariant()
  307.                FLData()
  308.  
  309.  
  310.           A FlexList  can be accessed as  a stack, queue, list,  or even an
  311.           array once it  has nodes  in it, interchangeably.   The  FlexList
  312.           header keeps track  of everything  so if your  pushing data  onto
  313.           your "stack" at one moment,  you can recall an element  from your
  314.           "array"  the  next.   You can  sort  your FlexList,  then perform
  315.           various other operations on it and FLisSorted will tell you if it
  316.           is still sorted.   You can  set an upper  limit on the  number of
  317.           nodes a FlexList is allowed to hold with FLsetMaxNodes.  You will
  318.           come to know what each function does with time.
  319.  
  320.  
  321.                           FlexList Stack and Queue Functions
  322.  
  323.           A stack provides  LIFO (Last In, First Out)  storage.  A complete
  324.           set of  stack  primitives is  provided.   These  functions  don't
  325.           disturb the queue, list,  or array structure of  a FlexList.   In
  326.           other words, you can access your  FlexList as a stack at any time
  327.           and revert  back  to accessing  it  as a  queue, list,  or  array
  328.           freely.
  329.  
  330.  
  331.                FLpushN()           FLpushD()           FLpopN()
  332.                FLpopD()            FLtopD()            FLinsQN()
  333.                FLinsQD()           FLfrontD()          FLrearD()
  334.  
  335.  
  336.           A queue provides FIFO (First In, First Out) storage.  Notice that
  337.           some  of the stack functions  double up here  as queue functions,
  338.           e.g.  FLpopD, FLtopD.   Also I  have again  included some  of the
  339.           FlexList header access functions, i.e. FLfrontD and FLrearD which
  340.       return  pointers  to  the  data  in  the  first  and  last  nodes
  341.       respectively.   Basically I'm suggesting various  logical ways to
  342.       categorize  FlexList functions to help you remember them.  You'll
  343.       find that several functions may belong in multiple categories.
  344.  
  345.           The  functions ending with  "N" work directly  with the FlexNodes
  346.           which contain your data.   For an example, suppose that  you want
  347.           to  pop your stack directly into your  queue.  The following code
  348.           shows how.
  349.  
  350.                #include  <stdio.h>      /*  printf()  */
  351.                #include  <flexlist.h>
  352.  
  353.  
  354.  
  355.  
  356.  
  357.                FlexList s, q;
  358.                int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  359.                int *iptr;
  360.                #define  inT0   ((int *)0)
  361.  
  362.                main()         /*  count to ten the hard way  */
  363.                {
  364.                     (void) FLunpack(&s,sizeof(a[0]),sizeof(a)/
  365.                          sizeof(a[0]),a);
  366.                     (void) FLfixed(&q,FLsizeofNodeData(&s));
  367.                     while ((iptr = FLinsQN(&q,FLpopN(&s))) != inT0)
  368.                          (void) printf("\n  %d",*iptr);
  369.                     (void) FLclear(&s);
  370.                     (void) FLclear(&q);
  371.                     return 0;
  372.                }
  373.  
  374.           In  this example the stack is constructed by "exploding" an array
  375.           of integers  into a FlexList.   Next the queue is  constructed to
  376.           hold the same  size data as the stack.  Then  the stack is popped
  377.           directly into  the queue and a  pointer to the data  in the newly
  378.           inserted  queue  node  is  captured  and  tested  to control  the
  379.           looping!   I print the integer  each time so you can  see that it
  380.           made it into  the queue.  Did  you notice how I  defined the NULL
  381.           integer pointer?  I did that  here so you'll know what's going on
  382.           when you see other NULL pointers elsewhere.
  383.  
  384.  
  385.                                FlexList List Functions
  386.  
  387.           Any  FlexList  can be  treated as  a  doubly linked  list thereby
  388.           providing sequential  storage.   You can insert  nodes or  delete
  389.           them.   The FlexList header maintains a current node pointer that
  390.           lets the list functions  know where the insertion or  deletion is
  391.           to  take place.   Stack  and queue  functions don't  disturb this
  392.           current  pointer unless of course  it points to  the top/front of
  393.           the  stack/queue and that node  is popped/removed.   In that case
  394.           the current node becomes undefined.
  395.  
  396.  
  397.                FLmkcur()           FLinsN()            FLinsD()
  398.                FLinsSortN()        FLinsSortD()        FLdelN()
  399.                FLdelD()            FLnextD()           FLprevD()
  400.                FLcurNum()          FLcurrentD()        FLcompare()
  401.                FLsetCompare()
  402.  
  403.  
  404.  
  405.  
  406.  
  407.           FlexList  nodes  are  numbered starting  at  one.    When FLnextD
  408.           reaches  the end of  the list the  current node number  is set to
  409.           zero which is  said to be undefined and FLnextD  returns the NULL
  410.           void pointer.    On the  next call  to FLnextD  the current  node
  411.           becomes  one, that  is  of  course  if there  are  nodes  in  the
  412.           FlexList!  FLprevD works  the same way.  This  mechanism makes it
  413.           handy to walk  around lists pausing at the ends.   If you want to
  414.           set the current pointer to a particular node, use FLmkcur.
  415.  
  416.           Oh, I guess I should mention again that you can store any type of
  417.           data in a  FlexList not just integers.   Let's see something like
  418.           that last example again with strings.
  419.  
  420.  
  421.                #include  <stdio.h>      /*  printf()  */
  422.                #include  <flexlist.h>
  423.  
  424.                FlexList l;
  425.                char *a[] = { "Now is the time", "for all good",
  426.                     "programmers to cut", "their coding time",
  427.                     "with FlexList!"
  428.                };
  429.                char **sptr;
  430.                #define chaRR0 ((char **)0)
  431.  
  432.                main()    /*  PSW propaganda  */
  433.                {
  434.  
  435.                     (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
  436.                          sizeof(a[0]),a);
  437.                     while ((sptr = FLnextD(&l,(void *)0)) != chaRR0)
  438.                          (void) printf("\n  %s",*sptr);
  439.                     (void) FLmkcur(&l,FLnodes(&l));
  440.                     while (FLdelD(&l,(void *)0))
  441.                          /* null statement */;  /*  FLclear(&l);  */
  442.                     (void) printf("\n There should be zero nodes now: %d",
  443.                          FLnodes(&l));
  444.                     return 0;
  445.                }
  446.  
  447.  
  448.           In  this  program I  exploded a  vector of  char pointers  into a
  449.           FlexList.  Whenever FlexLists are constructed the current node is
  450.           set  as undefined so  FLnextD starts walking  across the FlexList
  451.           beginning with the first node.  FLnextD will copy the data in the
  452.           next node to whatever address you specify in the second parameter
  453.           unless of course it is  the NULL address!  When you  are browsing
  454.           the  reference chapter  you will  notice many  FlexList functions
  455.           that copy data  to/from a FlexNode when an address  is given.  If
  456.           the NULL address is specified the copying action is inhibited but
  457.           the function otherwise performs its purpose.  In this example
  458.  
  459.  
  460.  
  461.  
  462.  
  463.           FLnextD is inhibited from copying any data but it never the  less
  464.           moves the  current pointer  on to  the next node.   FLnextD  also
  465.           returns a void pointer  to the data in the next node.   I capture
  466.           that  pointer in order to print the  string but I'm also using it
  467.           to control the loop.
  468.  
  469.           All FlexList  functions return  either pointers or  integer types
  470.           that are  non zero  only when  the respective  function completes
  471.           successfully.  The void pointers returned from FlexList functions
  472.           point to  the user data  in focus.   In  the case  of FLnextD  it
  473.           points to the user  data in the  next node.   I have simply  type
  474.           casted this  pointer to a pointer to the type of data I'm storing
  475.           in the FlexNodes  in order to gain access  to that data.   As you
  476.           can see FlexList functions  allow you to access you data by value
  477.           (copy) or by reference (pointer) as well as moving nodes directly
  478.           between/within FlexLists.
  479.  
  480.           Back  to our example, FLmkcur  moves the current  node pointer to
  481.           the last node in the list.  FLmkcur also returns a pointer to the
  482.           data in  the last node but I choose to  ignore it.  Now FLdelD is
  483.           used  to  delete the  nodes from  the list.   FLdelD  removes the
  484.           current node after copying its contents  to the address specified
  485.           (copying  is inhibited here by the NULL address) and then unlinks
  486.           the  FlexNode from  the FlexList  and  proceeds to  deallocate it
  487.           making the previous node in the FlexList the new current node.  I
  488.           might add that FLinsD does the exact opposite, i.e. inserts a new
  489.           FlexNode after  the  current node  making the  new node  current.
  490.           Again the stack and queue structure of FlexList is undisturbed by
  491.           any list functions invoked on the FlexList and vice versa.
  492.  
  493.  
  494.                             FlexList Search/Sort Functions
  495.  
  496.           The Search/Sort functions  allow you to  lookup and/or sort  your
  497.           data.  Every FlexList has a user definable compare function.  Use
  498.           FLsetCompare  to  set  a  FlexList's  internal  compare  function
  499.           pointer.   To facilitate sorting define your  compare function to
  500.           return -1,  0,  or 1  to indicate  whether the  first data  being
  501.           compared  is less  than, equal  to, or  greater than  the second,
  502.           respectively.   The compare function is also used for matching in
  503.           the  FLfind...()  functions.    Please  note  that  most  of  the
  504.           functions mentioned  here modify  the current node  setting, thus
  505.           they interact with the list functions mentioned earlier.
  506.  
  507.  
  508.                FLinsSortN()        FLinsSortD()        FLfindFirstD()
  509.                FLfindNextD()       FLfindLastD()       FLfindPrevD()
  510.                FLsort()            FLisSorted()        FLunSort()
  511.                FLcompare()         FLsetCompare()
  512.  
  513.  
  514.  
  515.  
  516.  
  517.           Use FLinsSortD/N() to perform insertion sorts.  If the list isn't
  518.           sorted then FLsort will be called automatically before attempting
  519.           the insertion.  If  a compare function pointer hasn't  been setup
  520.           then the insertion is aborted.
  521.  
  522.           The  FLfind...D  functions work  regardless  if  the FlexList  is
  523.           sorted or not.  If it  is sorted then the binary search algorithm
  524.           is used to find the first/last  matching data and a linear search
  525.           is  used to  find  the next/previous  match stopping  immediately
  526.           after the first mismatch.  If the FlexList is not sorted then the
  527.           linear search algorithm  is used to find  the first/last matching
  528.           data and again to  find the next/previous match stopping  only at
  529.           the ends of the list.
  530.  
  531.           Use FLsort or FLsetCompare to setup the compare function pointer.
  532.           If  the NULL  compare  function pointer,  FLcompare0 (defined  in
  533.           flexlist.h),  is  passed  to  FLsort then  the  previous  compare
  534.           function pointer is  used to sort the  list.  Call  FLisSorted to
  535.           determine  whether a FlexList is still sorted from its last sort.
  536.           For example, suppose you sort  a list and pop some nodes  off the
  537.           front.   Well that won't  cause the  FlexList to  be unsorted  so
  538.           FLisSorted will return  true.  But if you push  some data onto it
  539.           treating  it like a  stack, that may  or may not  ruin the sorted
  540.           order.  FLisSorted  will return  false because it  can no  longer
  541.           guarantee that  the FlexList is sorted.   You need to  be careful
  542.           though since FLnextD, FLprevD, and FLmkcur won't cause FLisSorted
  543.           to reset to false even though you might have modified the data in
  544.           the FlexNode via the returned void pointer!  In that case you may
  545.           want to call  FLunSort to reset FLisSorted so that it will return
  546.           false.
  547.  
  548.           The following example performs an unsorted linear search followed
  549.           by an alphabetical sort.
  550.  
  551.  
  552.                #include  <stdio.h>      /*  printf()  */
  553.                #include  <string.h>     /*  strstr(), strcmp()  */
  554.                #include  <flexlist.h>
  555.  
  556.                int strStr(char *s, char *t)
  557.                {
  558.                     return !(int)strstr(s,t);
  559.                }
  560.  
  561.                main()
  562.                {
  563.                     FlexList l;
  564.                     char *s, sbuf[80];
  565.                     char *mask = "overtime";
  566.                     int i;
  567.  
  568.  
  569.  
  570.  
  571.  
  572.                     (void) FLstr(&l);
  573.                     (void) FLinsD(&l,"Once upon a time there were three");
  574.                     (void) FLinsD(&l,"programmers, who worked");
  575.                     (void) FLinsD(&l,"allot of overtime!");
  576.                     (void) FLinsQD(&l,"That was before the FlexList Fox");
  577.                     (void) FLinsQD(&l,"joined the staff!");
  578.                     for ((void)FLmkcur(&l,0); FLnextD(&l,sbuf);
  579.                          /* no reinit */)
  580.                          (void) printf("\n Node: %d. %s",
  581.                               FLcurNum(&l),sbuf);
  582.                     (void) FLsetCompare(&l,FLcomparE(strStr));
  583.                     if ((s = FLfindFirstD(&l,mask)) != (char *)0)
  584.                          (void) printf("\n Mask: \"%s\" found in \
  585.                               node: %d. %s",mask,FLcurNum(&l),s);
  586.                     (void) FLsort(&l,FLcomparE(strcmp));
  587.                     for (i = 1; FLrecallD(&l,sbuf,(unsigned)i); i++)
  588.                          (void) printf("\n Node: %d. %s",
  589.                               FLcurNum(&l),sbuf);
  590.                     (void) FLclear(&l);
  591.                     return 0;
  592.                }
  593.  
  594.  
  595.           This  program  constructs  a   variant  FlexList  via  the  macro
  596.           constructor  FLstr which expands into  a call to  FLvariant.  The
  597.           FlexNodes  in  this  FlexList are  only  be  enough  to hold  the
  598.           character   strings  passed  as   parameters  (please  note  that
  599.           character  string constants  are  pointers to  the  strings so  I
  600.           didn't  use the  address of,  "&", operator!)   I didn't  use the
  601.           FLunpack  constructor  because  it  builds  fixed  size  FlexNode
  602.           (homogeneous) FlexLists - an array has fixed cell sizes.  Instead
  603.           I inserted the strings one by one and queued the last two just to
  604.           be different.
  605.  
  606.           The  first "for loop" uses FLnextD to  verify the contains of the
  607.           FlexNodes.  FLnextD  only copies the  string and zero  terminator
  608.           thanks  to the  virtual function  table's function  pointers (see
  609.           FLvariant  in  the reference  chapter  to  see how  to  construct
  610.           heterogenous lists).  Be sure that the variable whose address you
  611.           pass to FLnextD  is big  enough to accommodate  the largest  data
  612.           that  can be read!    You should  have noticed that  I had to use
  613.           FLmkcur(&l,0) since the current node pointer is still pointing to
  614.           the  last node inserted and not  the last node queued.  Remember,
  615.           queue  functions don't disturb  the list structure  - the current
  616.           node  concept  is  part of  the  list  structure,  not the  queue
  617.           structure!
  618.  
  619.           Since the list is  not sorted, FLfindFirstD searches in  a linear
  620.           fashion  starting with  the  first node,  internally calling  the
  621.           compare function  setup with FLsetCompare.   The FLcomparE macro,
  622.           defined in flexlist.h, type casts strStr to the precise function
  623.  
  624.  
  625.  
  626.  
  627.  
  628.           pointer type required by both FLsetCompare and FLsort.  My strStr
  629.           returns 0 if t is within s.   Since only a linear search will  be
  630.           used  with  this compare  function,  it  doesn't matter  that  is
  631.           doesn't return -1 or 1 to indicate less than or greater than.
  632.  
  633.           The  program proceeds with  a standard alphabetical  sort and the
  634.           resultant ordering  is displayed with FLrecallD,  an array access
  635.           function which you'll see in the next section.
  636.  
  637.  
  638.                                FlexList Array Functions
  639.  
  640.           An array provides  randomly accessible storage.   A FlexList  can
  641.           also be accessed as an array once it has nodes in it.
  642.  
  643.  
  644.                FLstoreD()          FLrecallD()         FLmkcur()
  645.                FLcurrentD()        FLcurNum()
  646.  
  647.  
  648.           The  last node  accessed  becomes the  new  current node.    When
  649.           randomly accessing  a FlexList,  FLmkcur is called  internally by
  650.           both  FLstoreD and FLrecallD to make  the requested node current.
  651.           FLmkcur  determines which  pointer (front,  current, or  rear) is
  652.           closest  to the requested node.   It then  follows the FlexList's
  653.           linkage from  that closest pointer  to the newly  requested node.
  654.           The current pointer is left  positioned at the new node.   Please
  655.           note that array, search/sort, and list functions interact in that
  656.           they  all work with and  modify the current  node setting.  Stack
  657.           and queue functions are independent, however.
  658.  
  659.  
  660.                             FlexList Compaction Functions
  661.  
  662.           Sometimes  you want  to work with  a list, other  times it's more
  663.           convenient  to work with an array.  Although FlexList allows this
  664.           chameleon behavior, your application  may progress in stages that
  665.           favor a  linked list at one  point and a conventional  C array at
  666.           another.   FlexList has  "compaction" functions for  converting a
  667.           conventional array into a  FlexList or vice versa,  thus allowing
  668.           you to optimize the performance of your application.
  669.  
  670.  
  671.                          FLunpack()          FLunpackNew()
  672.                          FLpack()            FLpackPtrs()
  673.  
  674.  
  675.           You  can  think  of  the FLunpack/FLunpackNew  as  exploding  the
  676.           conventional  C array  into  a FlexList.    Think of  the  FLpack
  677.           function as doing the exact opposite or imploding a FlexList into
  678.           a   conventional  C  array.    Arrays  compacted  by  FLpack  and
  679.           FLpackPtrs must be explicitly deleted with a call to free when no
  680.  
  681.  
  682.  
  683.  
  684.  
  685.           longer  needed  if  their memory  is  ever  to  be recovered  for
  686.           subsequent  reuse.  FLpackPtrs  returns an array of void pointers
  687.           pointing  to  the data  in the  FlexNodes.   This  array  is NULL
  688.           terminated to facilitate subsequent processing.
  689.  
  690.           For  the  last  example program  we'll  clone  a  vector of  char
  691.           pointers but the clone will have the advantage over its parent of
  692.           being sorted in alphabetical order.
  693.  
  694.  
  695.                #include  <stdio.h>      /*  printf()  */
  696.                #include  <stdlib.h>     /*  free()  */
  697.                #include  <string.h>     /*  strcmp()  */
  698.                #include  <flexlist.h>
  699.  
  700.                char *a[] = { "one", "two", "three", "four", "five" };
  701.                char **A;
  702.  
  703.                int strCmp(char **s, char **t)
  704.                {
  705.                     return strcmp(*s,*t);
  706.                }
  707.  
  708.                main()
  709.                {
  710.                     FlexList l;
  711.                     int i;
  712.  
  713.                     (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
  714.                          sizeof(a[0]),a);
  715.                     (void) FLsort(&l,FLcomparE(strCmp));
  716.                     A = FLpack(&l);
  717.                     for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
  718.                          (void) printf("\n a[%d] = %s",i,a[i]);
  719.                     if (A)  {
  720.                          for (i = 0; i < FLnodes(&l); i++)
  721.                               (void) printf("\n A[%d] = %s",
  722.                                    i,((char **)A)[i]);
  723.                          free(A);
  724.                     }
  725.                     (void) FLclear(&l);
  726.                     return 0;
  727.                }
  728.  
  729.           Remember that the FlexNodes in this program contain char pointers
  730.           and  that the  compare function  is passed  pointers to  the char
  731.           pointers, that is why the strCmp has to dereference them.
  732.  
  733.           Many  commercial C toolbox  functions require  vector parameters.
  734.           With FlexList's  compaction functions you can  manipulate vectors
  735.           on the  fly.  The  vectors can be stored  in files and  loaded as
  736.           needed via a FlexList and subsequent packing.  The vector can
  737.  
  738.  
  739.  
  740.  
  741.  
  742.       then be kept around only during the computation phase in which it
  743.       is  needed.    Large,  oversized,  static  vectors  need  not  be
  744.       allocated  at compile  time to  cope with  worst case  scenarios,
  745.       thereby   consuming  precious  data  segment  space  within  your
  746.       program.
  747.  
  748.  
  749.                           Accessing FlexList Nodes and Data
  750.  
  751.           Now that we've finished categorizing FlexList functions along the
  752.           lines  of  its  hybrid  stack-queue-list-array  structure,  let's
  753.           rethink  what we've  seen  in  terms  of  how  the  FlexList  was
  754.           accessed,  namely: by  value, by  reference, and  by node.   This
  755.           gives us a second way to analyze FlexList functions.
  756.  
  757.           "By value" implies that the data is copied to or from a FlexNode.
  758.           For example, with FLpopD the top  node of the stack is popped and
  759.           the  data  is  copied to  the  address  specified  by the  second
  760.           parameter before the node is freed and returned to the  heap.  We
  761.           are in effect  accessing the data in the top  node by value since
  762.           we are retrieving, in actuality, a copy of it.
  763.  
  764.                     FLpopD(&s,&i);   /*  i is same type in FlexNode  */
  765.  
  766.           "By  reference" implies that the data in the FlexNode is accessed
  767.           by pointer.   You will need  to type cast these  void pointers to
  768.           pointers  to the type  of data you have  stored in the FlexNodes.
  769.           Suppose we're walking backward across a FlexList of integers with
  770.           the code:
  771.  
  772.                     while ((iptr = FLprevD(&l,(void *)0)) != (int *)0)
  773.                          (void) printf("\n  %d",*iptr);
  774.  
  775.           All void pointers  returned by FlexList  functions point to  user
  776.           data.   Thus the data can  be modified directly.   "By reference"
  777.           functions are provided to speed  up processing.  Without  pointer
  778.           access you would have to first copy the data out of the FlexNode,
  779.           modify it and then copy it back.  With large data structures that
  780.           could prove to be quite inefficient.  Please note the FLnextD and
  781.           FLprevD are purely "by  reference" when called with  their second
  782.           parameters  equal to  the  NULL address.   Actually  all FlexList
  783.           functions returning void pointers  allow access "by reference" in
  784.           combination perhaps with "by value" access.
  785.  
  786.           In  queuing  network  simulations  you will  want  to  move nodes
  787.           between FlexLists rapidly.   Without access  "by node" you  would
  788.           have to "FLpopD" the  source queue and "FLinsQD" the  destination
  789.           queue.   This would entail copying  the data from the  front node
  790.           into  a  local   variable  of  the   same  type,  unlinking   and
  791.           deallocating the  FlexNode, then reallocating a  new FlexNode and
  792.           linking it into the other queue and finally copying the data from
  793.           the local variable back into the node.  The faster way is to
  794.  
  795.  
  796.  
  797.  
  798.  
  799.           unlink  the FlexNode from the source queue and relink it directly
  800.           into the destination queue, e.g.
  801.  
  802.                     FLinsN(&dstQ,FLpopN(&srcQ));
  803.  
  804.           If dstQ is already full then the node popped from srcQ is lost in
  805.           the twilight  zone.  A  better approach would  be to prevent  the
  806.           chance of FlexNodes being left dangling:
  807.  
  808.                     while (FLnotFull(&dstQ) && FLnodes(&srcQ))
  809.                          (void) FLinsN(&dstQ,FLpopN(&srcQ));
  810.  
  811.           The  "By node"  functions  unlink and  relink FlexNodes  directly
  812.           between  compatible FlexLists.   Compatible  in this  sense means
  813.           that  both  FlexLists  have   equal  sizeofNodeData  fields  (not
  814.           necessarily  initialized for  the  same data  type)  .   Use  the
  815.           FLsizeofNodeData function to read  the sizeofNodeData field.  Two
  816.           FlexLists could also be  considered to be compatible if  they are
  817.           both  variant FlexLists with compatible data.  I should point out
  818.           that  variant FlexLists  have  the sizeofNodeData  fields set  to
  819.           zero.  Be careful not to assume that two FlexLists are compatible
  820.           just because both sizeofNodeData  fields are equal to zero.   You
  821.           can  use  FLisVariant  to  retrieve the  virtual  function  table
  822.           pointer within the FlexList header.  If two variant FlexLists use
  823.           the same virtual function table, they are most likely compatible.
  824.           You  are  responsible  for   insuring  that  your  FlexLists  are
  825.           compatible.   Remember also,  FlexNodes unlinked with  a function
  826.           ending with "N" must be relinked with a function ending  with "N"
  827.           to a compatible FlexList or otherwise explicitly disposed of.
  828.  
  829.  
  830.                                        Summary
  831.  
  832.           Let's review what we learned starting with the points to remember
  833.           when programming with the FlexList tool.
  834.  
  835.                1.   Be sure to  include the FlexList  header in any  module
  836.                     that references FlexList functions.
  837.  
  838.                2.   Define your global,  static, and local stacks,  queues,
  839.                     lists,  etc.   as  "FlexList".    Define  your  dynamic
  840.                     versions as pointers to FlexLists, i.e. "FlexL".
  841.  
  842.                3.   Construct   your  FlexList   variable  with   a  static
  843.                     constructor function  and your FlexList pointer  with a
  844.                     dynamic constructor function.
  845.  
  846.  
  847.  
  848.  
  849.  
  850.                4.   The first parameter of all FlexList functions, with the
  851.                     exception of FLdelete, is an  address of a FlexList, or
  852.                     putting it another way, is a pointer to a FlexList.  If
  853.                     the function  is somehow  involved with the  copying of
  854.                     user  data, the address of the data is always passed in
  855.                     the second parameter.
  856.  
  857.                5.   All  FlexList  functions  return  either   pointers  or
  858.                     integers.   A returned value of  zero indicates failure
  859.                     of the function to complete its task.
  860.  
  861.                6.   Destruct all FlexLists when  they are no longer needed.
  862.                     Use  FLclear  on  global,  static,  or  local  FlexList
  863.                     variables and FLdelete on dynamic FlexLists.
  864.  
  865.                7.   Link your application with the compiled flexlist object
  866.                     module or the flexlist library you build.
  867.  
  868.  
  869.           Next,  let's  review  the  various  functions  available  in  the
  870.           FlexList tool.   FlexList functions can  be categorized according
  871.           to  the logical  nature  of a  FlexList's inherent  hybrid stack-
  872.           queue-list-array structure.
  873.  
  874.  
  875.                       FlexList Constructor/Destructor Functions
  876.  
  877.                FLfixed()           FLunpack()          FLvariant()
  878.                FLstr()             FLclear()
  879.  
  880.                FLfixedNew()        FLunpackNew()       FLvariantNew()
  881.                FLstrNew()          FLdelete()
  882.  
  883.  
  884.                            FlexList Header Access Functions
  885.  
  886.                FLfrontD()          FLcurrentD()        FLrearD()
  887.                FLcurNum()          FLnodes()           FLmaxNodes()
  888.                FLsetMaxNodes()     FLnotFull()         FLsizeofNodeData()
  889.                FLisSorted()        FLunSort()          FLcompare()
  890.                FLsetCompare()      FLisFixed()         FLisVariant()
  891.                FLData()
  892.  
  893.  
  894.                           FlexList Stack and Queue Functions
  895.  
  896.  
  897.                FLpushN()           FLpushD()           FLpopN()
  898.                FLpopD()            FLtopD()            FLinsQN()
  899.                FLinsQD()           FLfrontD()          FLrearD()
  900.  
  901.  
  902.  
  903.  
  904.  
  905.                    FlexList List Functions
  906.  
  907.                FLmkcur()           FLinsN()            FLinsD()
  908.                FLinsSortN()        FLinsSortD()        FLdelN()
  909.                FLdelD()            FLnextD()           FLprevD()
  910.                FLcurNum()          FLcurrentD()        FLcompare()
  911.                FLsetCompare()
  912.  
  913.  
  914.                             FlexList Search/Sort Functions
  915.  
  916.                FLinsSortN()        FLinsSortD()        FLfindFirstD()
  917.                FLfindNextD()       FLfindLastD()       FLfindPrevD()
  918.                FLsort()            FLisSorted()        FLunSort()
  919.                FLcompare()         FLsetCompare()
  920.  
  921.  
  922.                                FlexList Array Functions
  923.  
  924.                FLstoreD()          FLrecallD()         FLmkcur()
  925.                FLcurrentD()        FLcurNum()
  926.  
  927.  
  928.                             FlexList Compaction Functions
  929.  
  930.                FLunpack()          FLunpackNew()       FLpack()
  931.                FLpackPtrs()
  932.  
  933.  
  934.           Finally, FlexLists  can be  accessed "by value",  "by reference",
  935.           and  "by  node."   "By value"  entails the  copying of  user data
  936.           between the  FlexNodes  and user  specified  addresses.   If  the
  937.           address specified is NULL  than the copying of data  is inhibited
  938.           but  the function performs otherwise as expected.  The address is
  939.           always the  second parameter  of the FlexList  function requiring
  940.           it.  "By reference" infers that user data is manipulated directly
  941.           inside  a  FlexNode  via  a  pointer.    All  FlexList  functions
  942.           returning void pointers  allow "by reference" access.   "By node"
  943.           functions  allow  FlexNodes   to  be  yanked/inserted   from/into
  944.           FlexLists.   These functions are  named with "N"  suffixes.  Move
  945.           FlexNodes  only  between  compatible  FlexLists.     Don't  leave
  946.           FlexNodes  dangling: either  insert them  back into  a compatible
  947.           FlexList with an "N" function or explicitly free them.
  948.  
  949.  
  950.           By  now you should be ready to  start the planning and subsequent
  951.           coding  of  your  FlexList  application  with  the  help  of  the
  952.           reference chapter on  FlexList functions.   Later, when you  feel
  953.           comfortable  with FlexList,  you will  want to  try your  hand at
  954.           deriving your own variant FlexLists (lists that contain
  955.  
  956.  
  957.  
  958.  
  959.  
  960.           heterogeneous data).  Be sure to read the entry for FLvariant  in
  961.           the reference  chapter for  an explanation  of  writing your  own
  962.           FlexList  virtual functions  that accommodate  your heterogeneous
  963.           data.  The FlexList dynamic constructor entries, i.e. constructor
  964.           functions  ending with  "New",  explain how  to encapsulate  your
  965.           list-pertinent data within FlexList headers.
  966.